import time
import threading
import tkinter as tk
from tkinter import messagebox, ttk
from datetime import datetime
from firmware_upgrader import FirmwareUpgrader
from bin_loader import BinFirmwareUpdater
from hex_loader import FirmwareUpdater

class FirmwareUpgrade:
    def __init__(self, root, network_manager, file_processor, message_display, timestamp_var):
        self.root = root
        self.network_manager = network_manager
        self.file_processor = file_processor
        self.message_display = message_display
        self.timestamp_var = timestamp_var
        self.upgrade_in_progress = False
        self.upgrade_start_time = None
        self.upgrade_progress_var = None
        self.upgrade_progress_bar = None

    def show_upgrade_dialog(self):
        """显示升级参数设置对话框"""
        if not self.network_manager.connected:
            messagebox.showwarning("警告", "设备未连接，请先连接设备")
            return

        dialog = tk.Toplevel(self.root)
        dialog.title("固件升级参数设置")
        dialog.geometry("450x250")
        dialog.resizable(False, False)

        ttk.Label(dialog, text="固件升级参数设置", font=("微软雅黑", 12, "bold")).pack(pady=15)

        params_frame = ttk.LabelFrame(dialog, text="升级参数", padding=15)
        params_frame.pack(fill=tk.X, padx=20, pady=10)

        # 首地址输入
        ttk.Label(params_frame, text="首地址 (HEX):").grid(row=0, column=0, sticky=tk.W, pady=5)
        start_address_var = tk.StringVar(value="08000000")
        ttk.Entry(params_frame, textvariable=start_address_var, width=20).grid(row=0, column=1, padx=(10, 0), pady=5, sticky=tk.W)

        # 包长度输入
        ttk.Label(params_frame, text="包长度 (DEC):").grid(row=1, column=0, sticky=tk.W, pady=5)
        block_length_var = tk.StringVar(value="256")
        ttk.Entry(params_frame, textvariable=block_length_var, width=20).grid(row=1, column=1, padx=(10, 0), pady=5, sticky=tk.W)

        # 芯片类型选择
        ttk.Label(params_frame, text="芯片类型:").grid(row=2, column=0, sticky=tk.W, pady=5)
        chip_type_var = tk.StringVar(value="ch32v10x")
        chip_type_combo = ttk.Combobox(params_frame, textvariable=chip_type_var, state="readonly", width=18)
        chip_type_combo['values'] = ("ch32v10x", "ch32v30x")
        chip_type_combo.grid(row=2, column=1, padx=(10, 0), pady=5, sticky=tk.W)

        # 按钮框架
        button_frame = ttk.Frame(dialog)
        button_frame.pack(fill=tk.X, padx=20, pady=10)
        
        ttk.Button(
            button_frame, 
            text="开始升级", 
            command=lambda: self.start_upgrade(
                start_address_var.get(),
                block_length_var.get(),
                chip_type_var.get(),
                dialog
            )
        ).pack(side=tk.RIGHT, padx=5)
        
        ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(side=tk.RIGHT, padx=5)

    def start_upgrade(self, start_address, block_length, chip_type, dialog):
        """开始升级流程"""
        try:
            # 验证参数
            if not start_address.startswith('0x'):
                start_address = '0x' + start_address
            start_addr = int(start_address, 16)
            block_len = int(block_length)
            if block_len <= 0:
                raise ValueError("包长度必须大于0")

            # 创建进度窗口
            self._create_progress_window()
            dialog.destroy()
            
            # 执行升级
            self.upgrade_in_progress = True
            self.upgrade_start_time = time.time()
            thread = threading.Thread(
                target=self._execute_upgrade_process,
                args=(start_addr, block_len, chip_type),
                daemon=True
            )
            thread.start()
            
        except ValueError as e:
            messagebox.showerror("参数错误", f"无效的参数: {str(e)}")

    def _create_progress_window(self):
        """创建升级进度窗口"""
        # 如果已有进度窗口，先销毁
        if hasattr(self, 'progress_window') and self.progress_window.winfo_exists():
            self.progress_window.destroy()
            
        self.progress_window = tk.Toplevel(self.root)
        self.progress_window.title("固件升级进度")
        self.progress_window.geometry("400x200")

        progress_frame = ttk.Frame(self.progress_window, padding=20)
        progress_frame.pack(fill=tk.BOTH, expand=True)

        self.upgrade_progress_var = tk.StringVar()
        self.upgrade_progress_var.set("准备升级...")
        ttk.Label(progress_frame, textvariable=self.upgrade_progress_var).pack(pady=10)

        self.upgrade_progress_bar = ttk.Progressbar(
            progress_frame, 
            orient="horizontal",
            length=300,
            mode="determinate"
        )
        self.upgrade_progress_bar.pack(fill=tk.X, pady=10)

        ttk.Button(
            progress_frame,
            text="取消升级",
            command=lambda: [self._upgrade_failed("用户取消"), self.progress_window.destroy()]
        ).pack(pady=10)

    def _execute_upgrade_process(self, start_address, block_length, chip_type):
        """执行升级流程"""
        try:
            # 初始化升级器
            if self.file_processor.hex_loader:
                firmware_updater = FirmwareUpdater(self.file_processor.hex_loader)
            elif self.file_processor.bin_loader:
                if not self.file_processor.bin_loader.memory_data:
                    raise Exception("没有加载的BIN数据")
                firmware_updater = BinFirmwareUpdater(self.file_processor.bin_loader)
            else:
                raise Exception("请先加载固件文件")

            # 配置升级器
            firmware_upgrader = FirmwareUpgrader(
                self.network_manager.socket,
                firmware_updater
            )
            firmware_upgrader.chip_type = chip_type
            firmware_upgrader.set_callbacks(
                progress_callback=self._update_upgrade_progress,
                message_callback=self._display_upgrade_message,
                upgrade_status_callback=self._update_upgrade_status
            )
            firmware_upgrader.set_timeouts(
                connect_timeout=self.network_manager.CONNECT_TIMEOUT,
                handshake_timeout=10.0,
                data_send_timeout=120.0,
                response_timeout=10.0
            )

            # 设置消息回调
            self.network_manager.on_receive_message = firmware_upgrader.on_receive_message

            # 执行升级
            success = firmware_upgrader.execute_upgrade_process(start_address, block_length)
            self.network_manager.on_receive_message = None

            if success:
                self.root.after_idle(self._upgrade_success)
            else:
                self.root.after_idle(self._upgrade_failed, "升级失败")
                
        except Exception as e:
            self.root.after_idle(self._upgrade_failed, f"升级过程中发生错误: {str(e)}")
            self.network_manager.on_receive_message = None

    def _update_upgrade_progress(self, sent_bytes, total_bytes):
        """更新升级进度"""
        if self.upgrade_progress_bar and self.upgrade_progress_var:
            percent = int(sent_bytes / total_bytes * 100) if total_bytes else 0
            self.upgrade_progress_bar['value'] = percent
            
            elapsed = time.time() - self.upgrade_start_time if self.upgrade_start_time else 0
            remaining = 0
            if sent_bytes > 0 and elapsed > 0:
                remaining = (total_bytes - sent_bytes) * (elapsed / sent_bytes)
            
            elapsed_str = time.strftime("%H:%M:%S", time.gmtime(elapsed))
            remaining_str = time.strftime("%H:%M:%S", time.gmtime(remaining))
            
            self.upgrade_progress_var.set(
                f"升级进度: {sent_bytes}/{total_bytes} 字节 ({percent}%)\n"
                f"已用时间: {elapsed_str} | 预计剩余: {remaining_str}"
            )

    def _update_upgrade_status(self, in_progress):
        """更新升级状态"""
        self.upgrade_in_progress = in_progress

    def _display_upgrade_message(self, message):
        """显示升级消息"""
        self.message_display.config(state=tk.NORMAL)
        if self.timestamp_var.get():
            timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.message_display.insert(tk.END, f"[{timestamp}] ", "timestamp")
        self.message_display.insert(tk.END, f"升级: {message}\n", "server")
        self.message_display.config(state=tk.DISABLED)
        self.message_display.see(tk.END)

    def _upgrade_success(self):
        """升级成功处理"""
        self.upgrade_in_progress = False
        total_time = time.time() - self.upgrade_start_time if self.upgrade_start_time else 0
        messagebox.showinfo("升级成功", f"固件升级已完成!\n总用时: {total_time:.1f} 秒")
        self._display_upgrade_message(f"固件升级成功完成，总用时: {total_time:.1f} 秒")

    def _upgrade_failed(self, error_message):
        """升级失败处理"""
        self.upgrade_in_progress = False
        total_time = time.time() - self.upgrade_start_time if self.upgrade_start_time else 0
        messagebox.showerror("升级失败", f"固件升级失败: {error_message}\n已用时: {total_time:.1f} 秒")
        self._display_upgrade_message(f"固件升级失败: {error_message}，已用时: {total_time:.1f} 秒")
